# Openwrt 修改默认ip脚本分析 ## /etc/board.json生成 1. `etc/init.d/boot` ```bash boot() { /bin/config_generate } ``` 2. `/bin/config_generate` ```bash #!/bin/sh CFG=/etc/board.json . /usr/share/libubox/jshn.sh # /etc/board.json文件存在不存在或者为空,则调用 board_detect 生成该文件,否则往下进行 # 第一次启动肯定不会存在该文件,所以肯定执行 board_detect [ -s $CFG ] || /bin/board_detect || exit 1 [ -s /etc/config/network -a -s /etc/config/system ] && exit 0 ``` 3. `/bin/board_detect` ```bash #!/bin/sh CFG=$1 [ -n "$CFG" ] || CFG=/etc/board.json # 如果/etc/board.d/是个目录,且 /etc/board.json 文件存在不存在或者为空 # 变量/etc/board.d/下面的脚本,然后执行 [ -d "/etc/board.d/" -a ! -s "$CFG" ] && { for a in $(ls /etc/board.d/*); do [ -x $a ] || continue; $(. $a) done } [ -s "$CFG" ] || return 1 ``` 4. 在`/etc/board.d/`目录下脚本如下: - 02_network:来源 target/linux/mpc85xx/base-files/etc/board.d/02_network ```bash #!/bin/sh # Copyright (C) 2014-2015 OpenWrt.org . /lib/functions/uci-defaults.sh . /lib/functions.sh . /lib/functions/system.sh board_config_update # board=fsl,P2020RDB 来源dts compatible = "fsl,P2020RDB"; board=$(board_name) case "$board" in fsl,P2020RDB) # 这里把eth0 eth1 都设置为lan口 ucidef_set_interface_lan "eth0 eth1" ;; *) # 这里把eth0设置为lan口,把eth1 设置为wan口 ucidef_set_interfaces_lan_wan "eth0" "eth1" ;; esac board_config_flush exit 0 ``` **注意**:ucidef_set_interface_lan和ucidef_set_interfaces_lan_wan函数会生成`/etc/board.json`文件。这两个函数存放位置:`package/base-files/files/lib/functions/uci-defaults.sh` - `ucidef_set_interface_lan`函数 ```bash ucidef_set_interface_lan() { ucidef_set_interface "lan" device "$1" protocol "${2:-static}" } ``` - `ucidef_set_interfaces_lan_wan`函数 ```bash ucidef_set_interfaces_lan_wan() { local lan_if="$1" local wan_if="$2" ucidef_set_interface_lan "$lan_if" ucidef_set_interface_wan "$wan_if" } ``` - `ucidef_set_interface`函数 ``` 以ucidef_set_interface_lan "eth0 eth1" 为例说明该函数功能: - ucidef_set_interface "lan" device "eth0 eth1" protocol "${2:-static}" - $1 = lan - $2 = device - $3 = "eth0 eth1" - $4 = protocol - $5 = static ``` 下面分析代码 ```bash ucidef_set_interface() { # network=lan local network=$1; shift # 选中/etc/board.json 里面的 network下的lan节点 json_select_object network json_select_object "$network" # 此时$1=device while [ -n "$1" ]; do local opt=$1; shift # opt=device local val=$1; shift # val = "eth0 eth1" [ -n "$opt" -a -n "$val" ] || break # 如果 val是列表,会添加json数组 # 大概是这个样子 "ports": ["eth0", "eth1"], [ "$opt" = "device" -a "$val" != "${val/ //}" ] && { # 这里处理device 多个网口 桥接到lan json_select_array "ports" for e in $val; do json_add_string "" "$e"; done json_close_array } || { # lan下的"protocol"节点 json_add_string "$opt" "$val" } done # 下面如果 没有protocol 设置默认的值, if ! json_is_a protocol string; then case "$network" in lan) json_add_string protocol static ;; wan) json_add_string protocol dhcp ;; *) json_add_string protocol none ;; esac fi json_select .. json_select .. } ``` 经过上面的代码后,就会生成`/etc/board.json` ``` { "model": { "id": "fsl,P2020RDB", "name": "Freescale P2020RDB" }, "network": { "lan": { "ports": [ "eth0", "eth1" ], "protocol": "static" } } } ``` - 99-default_network:来源 package/base-files/files/etc/board.d/99-default_network ```bash #!/bin/sh # # Copyright (C) 2013-2015 OpenWrt.org # . /lib/functions/uci-defaults.sh board_config_update # 判断/etc/board.json里面是否有 network 节点,如果有直接退出,没有的话往下 json_is_a network object && exit 0 # 理论上不会到这,因为在 02_network 中肯定生成了 /etc/board.json中的network节点 # 能跑到这说明没有network 节点,这里会设置节点, # ucidef_set_interface_lan 'eth0' [ -d /sys/class/net/eth1 ] && ucidef_set_interface_wan 'eth1' board_config_flush exit 0 ``` ## config_generate继续分析 在上个章节第2步骤,通过`[ -s $CFG ] || /bin/board_detect || exit 1` 会生成默认的/etc/board.json文件,接下来会继续根据给json文件生成`/etc/config/network`,下面继续分析。 `/bin/config_generate`文件下面的内容: ```bash # 加载/etc/board.json文件到shell json_init json_load "$(cat ${CFG})" umask 077 # 如果network不存在或者为空 if [ ! -s /etc/config/network ]; then bridge_name="" # 创建该文件 touch /etc/config/network # 生成config interface 'loopback'和config globals 'globals'节点 generate_static_network # 获取json中的bridge 这里是空的,json里面没有bridge json_get_vars bridge [ -n "$bridge" ] && { # 由于是空的,所以不会到这里,但是如果不是空的 json_select bridge json_get_vars name macaddr generate_bridge "$name" "$macaddr" json_select .. bridge_name=$name } # 按照上面提到的json文件,这里keys=lan # 所以执行的是 bridge_name="" # generate_network lan $bridge_name json_get_keys keys network for key in $keys; do generate_network $key $bridge_name; done json_get_keys keys switch for key in $keys; do generate_switch $key; done fi ``` `generate_network`代码如下: ```bash addr_offset=2 generate_network() { local ports device macaddr protocol type ipaddr netmask vlan local bridge=$2 json_select network json_select "$1" json_get_vars device macaddr metric protocol ipaddr netmask vlan json_get_values ports ports json_select .. json_select .. [ -n "$device" -o -n "$ports" ] || return # Force bridge for "lan" as it may have other devices (e.g. wireless) # bridged [ "$1" = "lan" -a -z "$ports" ] && { ports="$device" } [ -n "$ports" -a -z "$bridge" ] && { uci -q batch <<-EOF add network device set network.@device[-1].name='br-$1' set network.@device[-1].type='bridge' EOF for port in $ports; do uci add_list network.@device[-1].ports="$port"; done [ -n "$macaddr" ] && { for port in $ports; do uci -q batch <<-EOF add network device set network.@device[-1].name='$port' set network.@device[-1].macaddr='$macaddr' EOF done } device=br-$1 type= macaddr="" } [ -n "$bridge" ] && { [ -z "$ports" ] && ports="$device" if [ -z "$vlan" ]; then bridge_vlan_id=$((bridge_vlan_id + 1)) vlan=$bridge_vlan_id fi generate_bridge_vlan $1 $bridge "$ports" $vlan device=$bridge.$vlan type="" } if [ -n "$macaddr" ]; then uci -q batch <<-EOF add network device set network.@device[-1].name='$device' set network.@device[-1].macaddr='$macaddr' EOF fi uci -q batch <<-EOF delete network.$1 set network.$1='interface' set network.$1.type='$type' set network.$1.device='$device' set network.$1.metric='$metric' set network.$1.proto='none' EOF case "$protocol" in static) local ipad case "$1" in lan) ipad=${ipaddr:-"192.168.10.1"} ;; *) ipad=${ipaddr:-"192.168.$((addr_offset++)).1"} ;; esac netm=${netmask:-"255.255.255.0"} uci -q batch <<-EOF set network.$1.proto='static' set network.$1.ipaddr='$ipad' set network.$1.netmask='$netm' EOF [ -e /proc/sys/net/ipv6 ] && uci set network.$1.ip6assign='60' ;; dhcp) # fixup IPv6 slave interface if parent is a bridge [ "$type" = "bridge" ] && device="br-$1" uci set network.$1.proto='dhcp' [ -e /proc/sys/net/ipv6 ] && { uci -q batch <<-EOF delete network.${1}6 set network.${1}6='interface' set network.${1}6.device='$device' set network.${1}6.proto='dhcpv6' EOF } ;; pppoe) uci -q batch <<-EOF set network.$1.proto='pppoe' set network.$1.username='username' set network.$1.password='password' EOF [ -e /proc/sys/net/ipv6 ] && { uci -q batch <<-EOF set network.$1.ipv6='1' delete network.${1}6 set network.${1}6='interface' set network.${1}6.device='@${1}' set network.${1}6.proto='dhcpv6' EOF } ;; esac } ```